package cn.baage.campus.config;

import cn.baage.campus.config.security.auth.WxProvider;
import cn.baage.campus.config.security.filer.RestAuthenticationTokenFilter;
import cn.baage.campus.config.security.handler.RestAccessDeniedHandler;
import cn.baage.campus.config.security.handler.RestUnauthorizedHandler;
import cn.baage.campus.config.security.service.BaseUserDetailsService;
import cn.baage.campus.config.security.service.WxUserDetailService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Arrays;


/**
 * @Description: SpringSecurity 配置
 * @Author: 八阿哥
 * @url: baage.cn
 * @Version: 1.0
 **/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final BaseUserDetailsService userDetailsService;
    private final WxUserDetailService wxUserDetailService;
    private final RestAuthenticationTokenFilter restAuthenticationTokenFilter;
    private final RestUnauthorizedHandler restUnauthorizedHandler;
    private final RestAccessDeniedHandler restAccessDeniedHandler;

    /**
     * 加密规则
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置 AuthenticationManager
     *
     * @param auth 认证管理器建造者
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置默认 认证处理器（可省略）
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    /**
     * 配置安全策略
     *
     * @param http 安全策略
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 需要鉴权认证
                .antMatchers("/auth/logout", "/auth/loginInfo").authenticated()
                .antMatchers("/posting/likePosting").authenticated()
                // 允许匿名登录
                .antMatchers("/auth/**").permitAll()
                .antMatchers("/doc.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs").permitAll()
                .antMatchers("/category/listAll").permitAll()
                .antMatchers("/posting/**").permitAll()
                .antMatchers("/comment/listComment").permitAll()
                // 其他请求需要鉴权认证
                .anyRequest().authenticated()
                .and()
                //不通过Session获取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 自定义 JWT 认证过滤器
        http.addFilterBefore(restAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        // 自定义异常处理
        http.exceptionHandling()
                .authenticationEntryPoint(restUnauthorizedHandler)
                .accessDeniedHandler(restAccessDeniedHandler);

        //关闭csrf
        http.csrf().disable();
    }


    /**
     * 认证处理器：用户名密码
     */
    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider(){
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        return daoAuthenticationProvider;
    }


    /**
     * 认证处理器：微信(网页应用需要，小程序不需要)
     */
    @Bean
    public WxProvider wxProvider(){
        WxProvider wxProvider = new WxProvider();
        wxProvider.setUserDetailsService(wxUserDetailService);
        return wxProvider;
    }

    /**
     * 定义认证管理器
     */
    @Override
    @Bean(name="sysAuthenticationManager")
    public AuthenticationManager authenticationManagerBean() {
        ProviderManager authenticationManager = new ProviderManager(Arrays.asList(daoAuthenticationProvider(), wxProvider()));
        authenticationManager.setEraseCredentialsAfterAuthentication(false);
        return authenticationManager;
    }


}